fix(vocab-quiz): UI cluster — anti-cheat + UX (#190 #192 #193 #194)#196
Merged
davidortinau merged 3 commits intomainfrom May 3, 2026
Merged
fix(vocab-quiz): UI cluster — anti-cheat + UX (#190 #192 #193 #194)#196davidortinau merged 3 commits intomainfrom
davidortinau merged 3 commits intomainfrom
Conversation
Stream A of the Vocabulary Quiz bug cluster. Single-file Razor changes (plus three resource entries) covering four issues: #190 — Distractor pool now drawn from the full filtered+deduped vocabulary scope, not just the active round. New `distractorScope` field captured in LoadVocabulary; GenerateChoiceOptions samples from it with a defensive vocabItems fallback. Guarantees 4 MC options even when only 1 word remains to learn. Split CreateChoiceOption into CreateChoiceOption(item) + CreateChoiceOptionForWord(word) to support sampling from raw VocabularyWord. #192 — Added explicit Submit button inside the text-entry form. Hidden once feedback is shown in non-correction mode; disabled while userInput is empty/whitespace. Wired through existing @onsubmit="SubmitTypedAnswer". New resource key VocabQuiz_SubmitAnswer (en: "Submit", ko: "제출"). #193 — Prompt audio now follows prompt direction. New helpers GetPromptAudioText / GetPromptAudioLanguage switch on promptUsesNativeLanguage and return the side actually shown as the prompt. PlayWordAudio and audioPromptAvailable now route through these helpers so audio can never leak the answer in native→target prompts. #194 — Removed TargetLanguageTerm and NativeLanguageTerm from the Learning Details info panel (anti-cheat). Panel is opened mid-quiz; showing either side leaks the answer. Status badge moved to its own div; only stats and metadata remain. Closes #190 Closes #192 Closes #193 Closes #194
) The Learning Details panel was rendering pre-streak-truth metadata (IsKnown, IsUserDeclared, VerificationState) alongside the current streak-based fields. Per Jayne's service-side repro tests on main, service math is clean — the '2 attempts / 50% accuracy' confusion in issue #189 was a UI-rendering artifact. Restructured the two stat grids into one streak-truth grid showing only the allowlist: TotalAttempts, CorrectAttempts, Accuracy, CurrentStreak, ProductionInStreak, EffectiveStreak, MasteryScore plus the status badge. Schema fields on VocabularyProgress (IsKnown, VerificationState, ProductionAttempts, RecognitionAttempts, etc.) are unchanged for backward compatibility — only the panel rendering is tightened. Audited RecordPendingAttemptAsync call sites (NextItem, override-to- correct, DisposeAsync): no double-invocation. The method is idempotent via 'if (pendingAttempt == null) return;' guard.
davidortinau
added a commit
that referenced
this pull request
May 3, 2026
- PR #196 (Stream A UI fixes): closes #189/#190/#192/#193/#194 - PR #198 (Stream B scoring fix): closes #191 - PR #195 (test-only draft): superseded, closed - Follow-ups filed: #197 (decouple Mastery from SessionRotation), #199 (test helper DifficultyWeight bug) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Stream A of the Vocabulary Quiz bug cluster — UI-only fixes in
src/SentenceStudio.UI/Pages/VocabQuiz.razorplus resource entries.Closes #189
Closes #190
Closes #192
Closes #193
Closes #194
Changes
#189 — Strip legacy field readouts from Learning Details panel
Per Jayne's service-side repro tests on
main(Repro189_SingleCorrectRecognitionAttempt_ProducesExpectedPanelStateandRepro189_SingleCorrectRecognition_LegacyProductionFieldsRemainZeroboth pass), the service math is clean. The "2 attempts / 50% accuracy" confusion was a UI-rendering artifact — the panel was showing pre-streak-truth metadata (IsKnown,IsUserDeclared,VerificationState) alongside the current streak fields, conflating two different mental models of "is this word known".Restructured the two stat grids in the panel into one streak-truth grid showing only the allowlist:
Schema fields (
IsKnown,VerificationState,ProductionAttempts,RecognitionAttempts, etc.) onVocabularyProgressare unchanged for sync/back-compat — only the rendering is tightened.Also audited
RecordPendingAttemptAsynccall sites (NextItem, override-to-correct,DisposeAsync): no double-invocation found. The method is idempotent via theif (pendingAttempt == null) return;guard followed bypendingAttempt = null;— calling it twice is a no-op on the second call. The sentence-shortcut path at line 980 deliberately records one attempt per credited sentence, which is correct.#194 — Anti-cheat: hide terms in Learning Details panel
The info (ⓘ) panel is opened mid-quiz. Previously it rendered the target word as a heading and the native gloss right under it — completely defeating the purpose of testing recognition. Now the panel shows ONLY the status badge and learning metadata. The terms are removed from this view entirely.
#190 — Multiple-choice always has 4 options
Pre-fix, distractors were drawn from
vocabItems(the active round). When the round was small (e.g. SRS DueOnly with 1–3 words), the user got 1–3 options, often making the answer obvious. Now we capture the FULL filtered+deduped vocabulary scope into a newdistractorScopefield duringLoadVocabulary, andGenerateChoiceOptionssamples from it. Verified e2e: with 7 review-due Korean words, the quiz now shows distractors like "to come out" / "to learn" / "cheese" alongside the correct answer drawn from the full 327-word vocab.#193 — Prompt audio follows prompt direction
Audio play button on the prompt previously called
GetTargetAudioText/GetTargetAudioLanguageregardless of direction. When the user has prompt direction set to native→target (English shown, Korean hidden), pressing play would speak the Korean answer — leaking the test. New helpersGetPromptAudioTextandGetPromptAudioLanguageswitch onpromptUsesNativeLanguageand return the actually-shown side.PlayWordAudioand theaudioPromptAvailablecheck now route through these helpers.#192 — Submit button for text-entry mode
Text-entry quiz mode previously required pressing Enter to submit. Added a visible Submit button inside the form. Disabled while input is empty; hidden once feedback is shown in non-correction mode. New resource key
VocabQuiz_SubmitAnswer("Submit" / "제출"). The button istype="submit"and routes through the existing@onsubmit="SubmitTypedAnswer"handler.Files changed
src/SentenceStudio.UI/Pages/VocabQuiz.razor— all five fixessrc/SentenceStudio.Shared/Resources/Strings/AppResources.resx—VocabQuiz_SubmitAnswer= "Submit"src/SentenceStudio.Shared/Resources/Strings/AppResources.ko.resx—VocabQuiz_SubmitAnswer= "제출"src/SentenceStudio.Shared/Resources/Strings/AppResources.Designer.cs— auto-regeneratedVerification
SentenceStudio.UI.csprojbuilds clean (0 errors)SentenceStudio.MacCatalyst.csprojnet10.0-maccatalyst builds clean (0 errors)SentenceStudio.WebApp.csprojbuilds clean (0 errors) — verified after Accurate and total attempt don't make sense #189 editmain; UI fix is mechanical (strip + reorganize fields). Visual surface is the same panel as Learning Details modal leaks the answer #194 — re-verification on the same offcanvas is low-risk.MasteryScore >= 0.50orCurrentStreak >= 3to trigger text-entry mode.Out of scope
VocabQuiz_IsKnown,VocabQuiz_Yes,VocabQuiz_Noare no longer referenced from this panel but remain in resx files; low-priority cleanup)